package com.starsoft.quant.strategy.index;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.starsoft.frame.util.DateUtil;
import com.starsoft.frame.util.MapUtil;
import com.starsoft.quant.bean.QuantDetail;
import com.starsoft.quant.executor.StrategyReport;
import com.starsoft.quant.strategy.StrategyImpl;
import com.starsoft.smdc.bean.SmdcMarketDaily;
import com.starsoft.smdc.bean.SmdcSecurity;

public class IndexStrategy extends StrategyImpl {
	private static final Logger logger = LoggerFactory.getLogger(IndexStrategy.class);
	
	private int YEAR_TO_VALUATE;

	@Override
	public StrategyReport handle() {
		YEAR_TO_VALUATE =  Integer.parseInt(modelContext.getModelParam("YEAR_TO_VALUATE"));
		
		List<SmdcSecurity> securityList = context.getSecurityList();
		List<QuantDetail> details = new ArrayList<>();
		for (SmdcSecurity security : securityList) {
			try {
				QuantDetail report = null;
				if(security.getSecId().equals("000985.ss")) report = combine(security, details);
				else  report = analysis(security);
				if (report != null) 
					details.add(report);
			} catch (Exception e) {
				logger.error(security.getSecId()+" " + DateUtil.toString(context.getCurrentDate()), e);
				context.getRunLog().append(security.getSecId()).append(" ");
				context.getRunLog().append(security.getSecName()).append(" ");
				context.getRunLog().append(DateUtil.toString(context.getCurrentDate())).append(" ");
				context.getRunLog().append(e.getMessage()+" ").append(e.getClass().toString()).append("\n");
			}
		}
		StrategyReport report = createReport(details);
		return report;
	}
	

	private QuantDetail analysis(SmdcSecurity security) {
		List<SmdcMarketDaily> markets = getHisMarket(security);
		if(markets.size()<250) return null;
		Date accBeginDate = markets.get(0).getId().getTradeDate();
		SmdcMarketDaily latestMarket = markets.get(markets.size()-1);
		
		List<Double> peList = new ArrayList<Double>();
		List<Double> pbList = new ArrayList<Double>();
		markets.forEach(market -> {
			peList.add(market.getPeWeighted());
			pbList.add(market.getPbWeighted());
		});
		Double pePercentitle = IndexCaculator.percentitle(peList, latestMarket.getPeWeighted());
		Double pbPercentitle = IndexCaculator.percentitle(pbList, latestMarket.getPbWeighted());
		Double[] fullIncome = IndexCaculator.getIncome(markets);
//		Double changePrice = IndexCaculator.priceChangeNDay(markets, 20);
		
		QuantDetail detail = createDetail(security, pePercentitle/2+pbPercentitle/2);
		detail.setCol1(String.valueOf(latestMarket.getPeWeighted()));
		detail.setCol2(String.valueOf(latestMarket.getPbWeighted()));
		detail.setCol3(String.valueOf(latestMarket.getRoeWeighted()==null?"":latestMarket.getRoeWeighted()));
		detail.setCol4(String.valueOf(latestMarket.getDiviWeighted()==null?"":latestMarket.getDiviWeighted()));
		detail.setCol5(String.valueOf(pePercentitle));
		detail.setCol6(String.valueOf(pbPercentitle));
		detail.setCol7(DateUtil.toString(accBeginDate));
		detail.setCol8(String.valueOf(fullIncome[0]==null?"":fullIncome[0]));
		detail.setCol9(String.valueOf(fullIncome[1]==null?"":fullIncome[1]));
//		detail.setCol10(String.valueOf(changePrice));
		detail.setCol11(String.valueOf(fullIncome[2]));
		detail.setCol12(String.valueOf(fullIncome[3]));
		
		Double oneMonth = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), 0, -1, 0));
		Double treeMonth = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), 0, -3, 0));
		Double sixMonth = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), 0, -6, 0));
		Double oneYear = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), -1, -0, 0));
		Double threeYear = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), -3, 0, 0));
		Double fiveYear = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), -5, 0, 0));
		Double thisYear = IndexCaculator.priceChangeNatualDay(markets, cn.hutool.core.date.DateUtil.beginOfYear(context.getCurrentDate()));
		
		detail.setCol13(String.valueOf(oneMonth));
		detail.setCol14(String.valueOf(treeMonth));
		detail.setCol15(String.valueOf(sixMonth));
		detail.setCol16(String.valueOf(oneYear));
		detail.setCol17(String.valueOf(threeYear));
		detail.setCol18(String.valueOf(thisYear));
		detail.setCol19(String.valueOf(fiveYear));
		return detail;
	}
	
	private List<SmdcMarketDaily> getHisMarket(SmdcSecurity security){
		String secId = security.getSecId();
		Date currentDate = context.getCurrentDate();
		Date beginDate = DateUtil.bumpDate(currentDate, -YEAR_TO_VALUATE, 0, 0);
		Date securityBeginDate = context.getSecurityService().getBeginDate(security);
		if(beginDate.before(securityBeginDate)){
			beginDate = securityBeginDate;
		}
		
		List<SmdcMarketDaily> markets = context.getMarketDailyService().getBetweenAnd(secId, beginDate, currentDate);
		Date lastTradeDate = markets.get(markets.size()-1).getId().getTradeDate();
		if(!DateUtil.isSameDay(currentDate, lastTradeDate)){
			markets.add(context.getMarket(secId));
		}
		IndexCaculator.valuationCaculate(markets);

		List<SmdcMarketDaily> marketsFilter = markets.stream().filter(t -> t.getPeWeighted() != null)
				.collect(Collectors.toList());
		return marketsFilter;
	}
	
	
	private QuantDetail combine(SmdcSecurity security, List<QuantDetail> details) {
		StrategyReport report = new StrategyReport();
		report.setDetails(details);
		QuantDetail q300 = report.getDetail("000300.ss");
		QuantDetail q500 = report.getDetail("000905.ss");
		QuantDetail q1000 = report.getDetail("000852.ss");
		Date currentDate = context.getCurrentDate();
		Date beginDate = DateUtil.bumpDate(currentDate, -YEAR_TO_VALUATE, 0, 0);
		List<SmdcMarketDaily> markets = context.getMarketDailyService().getBetweenAnd(security.getSecId(), beginDate, currentDate);
		
		if(markets.size()<250) return null;
		Date accBeginDate = markets.get(0).getId().getTradeDate();
		
		Double pe = 1/(0.5/getValue(q300,"col1")+ 0.25/getValue(q500,"col1")+ 0.25/getValue(q1000,"col1"));
		Double pb = 1/(0.5/getValue(q300,"col2")+ 0.25/getValue(q500,"col2")+ 0.25/getValue(q1000,"col2"));
		Double roe = 0.5*getValue(q300,"col3")+ 0.25*getValue(q500,"col3")+ 0.25*getValue(q1000,"col3");
		Double div = 0.5*getValue(q300,"col4")+ 0.25*getValue(q500,"col4")+ 0.25*getValue(q1000,"col4");
		Double pePercentitle = 0.5*getValue(q300,"col5")+ 0.25*getValue(q500,"col5")+ 0.25*getValue(q1000,"col5");
		Double pbPercentitle = 0.5*getValue(q300,"col6")+ 0.25*getValue(q500,"col6")+ 0.25*getValue(q1000,"col6");
		Double[] fullIncome = IndexCaculator.getIncome(markets);
		
		QuantDetail detail = createDetail(security, pePercentitle/2+pbPercentitle/2);
		detail.setCol1(String.valueOf(pe));
		detail.setCol2(String.valueOf(pb));
		detail.setCol3(String.valueOf(roe));
		detail.setCol4(String.valueOf(div));
		detail.setCol5(String.valueOf(pePercentitle));
		detail.setCol6(String.valueOf(pbPercentitle));
		detail.setCol7(DateUtil.toString(accBeginDate));
		detail.setCol8(String.valueOf(fullIncome[0]==null?"":fullIncome[0]));
		detail.setCol9(String.valueOf(fullIncome[1]==null?"":fullIncome[1]));
		detail.setCol11(String.valueOf(fullIncome[2]));
		detail.setCol12(String.valueOf(fullIncome[3]));
		
		Double oneMonth = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), 0, -1, 0));
		Double treeMonth = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), 0, -3, 0));
		Double sixMonth = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), 0, -6, 0));
		Double oneYear = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), -1, -0, 0));
		Double threeYear = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), -3, 0, 0));
		Double fiveYear = IndexCaculator.priceChangeNatualDay(markets, DateUtil.bumpDate( context.getCurrentDate(), -5, 0, 0));
		Double thisYear = IndexCaculator.priceChangeNatualDay(markets, cn.hutool.core.date.DateUtil.beginOfYear(context.getCurrentDate()));
		
		detail.setCol13(String.valueOf(oneMonth));
		detail.setCol14(String.valueOf(treeMonth));
		detail.setCol15(String.valueOf(sixMonth));
		detail.setCol16(String.valueOf(oneYear));
		detail.setCol17(String.valueOf(threeYear));
		detail.setCol18(String.valueOf(thisYear));
		detail.setCol19(String.valueOf(fiveYear));
		return detail;
	}
	
	private Double getValue(QuantDetail detail, String column){
		Double value = null;
		Object ob = MapUtil.getValue(detail, column);
		if(ob == null){
			return null;
		}
		if(ob instanceof Double){
			value = (Double) ob;
		} else if (ob instanceof String) {
			try {
				value = Double.parseDouble((String) ob);
			} catch (Exception e) {
				return null;
			}
		}
		if(Math.abs(value)>1)
		return Math.rint(value*100)/100;
		else return Math.rint(value*10000)/10000;
	}
	
}
